package com.xiyou.weblog.jwt.filter;


import com.xiyou.weblog.jwt.utils.JwtTokenHelper;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.security.SignatureException;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * @author xiyou
 * @description 授权过滤器
 */
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    @Resource
    private JwtTokenHelper jwtTokenHelper;

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private AuthenticationEntryPoint authenticationEntryPoint;

//    token 请求头中的 key 值
    @Value("${jwt.tokenPrefix}")
    private String tokenPrefix;
//    token 请求头中的 value 值前缀
    @Value("${jwt.tokenHeaderKey}")
    private String tokenHeaderKey;




    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();

        // 只验证admin开头的接口
        if (requestURI.startsWith("/admin")) {
            // 从请求头中获取 key 为 Authorization 的值
            String header = request.getHeader(tokenHeaderKey);

            if (StringUtils.startsWith(header,tokenPrefix)) {
                // 截取 Token 令牌
                String token = StringUtils.substring(header, 7);
                log.info("Token: {}",token);

                //判空Token
                if (StringUtils.isNotBlank(token)) {
                    try {
                        jwtTokenHelper.validateToken(token);
                    } catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e) {
                        // 抛出异常，统一让 AuthenticationEntryPoint 处理响应参数
                        authenticationEntryPoint.commence(request,response,new AuthenticationServiceException("Token 不可用"));
                        return;
                    }catch (ExpiredJwtException e) {
                        authenticationEntryPoint.commence(request,response,new AuthenticationServiceException("Token 已失效"));
                        return;
                    }

                    //从Token中解析出用户名
                    String username = jwtTokenHelper.getUsernameByToken(token);

                    if (StringUtils.isNotBlank(username)
                            && Objects.isEmpty(SecurityContextHolder.getContext().getAuthentication())) {

                        // 根据用户名获取用户详情信息
                        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

                        // 将用户信息存入 authentication，方便后续校验
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        // 将 authentication 存入 ThreadLocal，方便后续获取用户信息
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }

            }
        }

        // 继续执行写一个过滤器
        filterChain.doFilter(request, response);
    }


    /**
     * 上述代码中，我们自定义了一个 Spring Security 过滤器 TokenAuthenticationFilter，
     * 它继承了 OncePerRequestFilter，确保每个请求只被过滤一次。
     * 在重写的 doFilterInternal() 方法中来定义过滤器处理逻辑，
     * 首先，从请求头中获取 key 为 Authorization 的值，判断是否以 Bearer 开头，若是，截取出 Token,
     * 对其进行解析，并对可能抛出的异常做出不同的返参。最后，我们获取了用户详情信息，
     * 将用户信息存入 authentication，
     * 方便后续进行校验，同时将 authentication 存入 ThreadLocal 中，方便后面方便的获取用户信息。
     */
}
